"""
@Project ：TeachingInterfacePro 
@File    ：conftest.py
@IDE     ：PyCharm 
@Author  ：ceiling
@Date    ：2025/4/16 21:52 
"""
from logging import handlers
import pytest


import os.path
import logging
import os
import re
import subprocess
import time
import shutil

import psutil

from utils.LoadEnvUtil import LoadEnvUtil
from utils.SendMsgToFeiShuUtil import SendMsgToFeiShu
from utils.SendMsgToWorkWeiXin import SendMsgToWorkWeiXin

BASE_DIR = os.path.dirname(__file__)
print(BASE_DIR)


@pytest.fixture(scope="session")
def value():
    return {
        "article_name": None
    }


# 配置日志文件
# 初始化日志配置
def init_log_config():
    # 创建日志器
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)

    # 创建控制台处理器
    sh = logging.StreamHandler()

    # 创建文件处理器
    # 文件路径
    # Create file processor
    # File path
    log_dir = os.path.join(BASE_DIR, "log")
    os.makedirs(log_dir, exist_ok=True)  # 如果不存在就创建，存在就跳过
    log_path = os.path.join(log_dir, "log.log")

    fh = logging.handlers.TimedRotatingFileHandler(log_path, when="midnight", interval=1,
                                                   backupCount=7, encoding="UTF-8")
    # 创建格式化器
    f = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s"
    formatter = logging.Formatter(f)

    # 把格式化处理器添加到处理器当中
    sh.setFormatter(formatter)
    fh.setFormatter(formatter)

    # 把处理器添加到日志器当中
    logger.addHandler(sh)
    logger.addHandler(fh)


"""
pytest_terminal_summary 是 Pytest 的一个内置钩子函数，它允许你在测试会话结束时，定制化地输出总结信息到终端
这一方法在 Pytest 测试运行完成后被调用，适用于添加额外统计信息、运行结果分析或其他总结性输出
在终端执行 pytest 命令之后 测试会话结束时触发以下条件
执行上传测试报告到文档中心
企业微信通知相关人员并统计测试数据(用例总数、失败用例数、成功用例数、跳过用例数、运行会话耗时、点击跳转文档中心地址)

参数 exitstatus :
    0 所有测试通过
    1 至少有一个测试用例失败
    2 测试用例未被正确收集(可能是语法错误 文件路径错误等问题)
    3 用户手动中断测试执行
    4 pytest 的命令行参数错误
    5 pytest 未找到测试用例

"""

# 企业微信机器人 webhook
# webhook = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=" + LoadEnvUtil.get_env_params("WEBHOOK")
webhook = LoadEnvUtil.get_env_params("WEBHOOK")
# 通知描述
desc = LoadEnvUtil.get_env_params("DESCRIPTION")
# 通知企业微信人员 list 集合
# 艾特某一个人填入其手机号即可  @all表示艾特所有人 不需要可以去掉 ["15093643240", "@all"]
# notifier = ["15093643240"]
# 文档中心测试报告跳转地址
# address = LoadEnvUtil.get_env_params("DOCUMENT_CENTER")


def run_allure_server(results_dir):
    """后台启动 allure serve 服务"""
    allure_path = shutil.which("allure")
    if not allure_path:
        raise RuntimeError("找不到 allure 命令，请确认环境变量已配置，或手动设置 allure 路径。")
    # cmd = [allure_path, "serve", "-h", "0.0.0.0", "-p", str(port), results_dir]
    # subprocess.Popen(cmd)
    cmd = [allure_path, "serve", results_dir]
    process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
    pattern = re.compile(r"http://[^\s]+:\d+/")
    address = None

    # 监听输出
    while True:
        line = process.stdout.readline()
        if not line:
            break
        print(f"[Allure] {line.strip()}")  # 打印日志
        match = pattern.search(line)
        if match:
            address = match.group(0)
            break

    return address


def kill_allure_serve():
    """查找并杀掉已有 allure serve 进程"""
    for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
        try:
            if 'allure' in proc.info['name'] or \
               (proc.info['cmdline'] and 'serve' in proc.info['cmdline']):
                print(f"[INFO] 发现旧 Allure 进程，已终止 PID: {proc.pid}")
                proc.kill()
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue


# 获取所有失败的用例 打印出来
def get_failed_tests_list(failed_tests, stats):
    if failed_tests > 0:
        failed_case_list = []
        print("\n==== 失败用例列表 ====")
        for report in stats.get("failed", []):
            print(f"- {report.nodeid}")
            failed_case_list.append(report.nodeid)
        return failed_case_list
    else:
        return "无"


def pytest_terminal_summary(terminalreporter, exitstatus):
    """在 Pytest 会话结束时计算总耗时并统计结果"""
    end_time = time.time()
    # 用 config 共享的 start_time
    started_time = terminalreporter._sessionstarttime
    total_time = round(end_time - started_time, 2)  # 保留两位小数的总耗时
    # 控制台的输出时间包括pytest插件加载 插件运行 测试用例运行 钩子函数运行 等所有时间综合
    # 在此统计的仅仅是 pytest 会话执行前后时间 不包括插件加载 失败重跑 钩子函数运行完毕的时间
    print(f"\n仅测试会话运行耗时: {total_time:.2f} 秒")
    print("\n==== pytest 会话结束 ====")

    # 获取测试结果统计
    stats = terminalreporter.stats

    skipped_tests = len(stats.get("skipped", []))  # 跳过测试数量
    failed_tests = len(stats.get("failed", []))    # 失败测试数量
    error_tests = len(stats.get('error', []))      # 错误测试数量
    passed_tests = len(stats.get("passed", []))    # 成功测试数量

    total_tests = terminalreporter._numcollected   # 总测试数量

    failed_test_cases_list = get_failed_tests_list(failed_tests, stats)

    print("\n==== 测试统计 ====")
    print(f"总测试用例数量: {total_tests}")
    print(f"成功: {passed_tests}")
    print(f"失败: {failed_tests}")
    print(f"失败: {error_tests}")
    print(f"跳过: {skipped_tests}")

    # 根据不同的退出状态输出不同的信息
    if exitstatus == 0:
        print("所有测试通过！")
    elif exitstatus == 1:
        print("有测试失败，请检查日志！")
    elif exitstatus == 2:
        print("测试用例未被正确收集，请检查路径或语法错误！")
    elif exitstatus == 3:
        print("测试被手动中断！")
    else:
        print("未知错误，请检查配置或环境问题。")

    # 启动 Allure 服务
    try:
        # print("\n正在检查是否有旧的 Allure 进程...")
        # kill_allure_serve()

        results_dir = "./report/allure-data"  # 你的报告路径
        print("\n启动 Allure 报告服务中...")
        # 获取局域网访问地址
        address = run_allure_server(results_dir)
        print(f"Allure 报告地址: {address}")
    except Exception as e:
        print(f"启动 Allure 报告失败: {e}")
        address = "Allure 服务启动失败"

    """
    企业微信通知
    """
    try:
        open_notifier = LoadEnvUtil.get_env_params("OPEN_OFFICER_NOTIFICATION", "false").lower()
        if open_notifier == "true":
            # 通知结果
            SendMsgToFeiShu().send_test_results_msg(webhook, desc, total_tests, passed_tests, failed_tests, error_tests,
                                                    skipped_tests, total_time, failed_test_cases_list, address)
            notifier = LoadEnvUtil.parse_notifier_officer("NOTIFIER_OFFICER", "@all")
            # 通知具体人员
            SendMsgToFeiShu().send_notifying_officer(webhook, notifier)
    except Exception as e:
        print(f"企业微信通知失败, 错误信息: {e}")



